package fem2d;

import java.io.IOException;

import org.junit.Test;

import fem2.AbstractStructuralStaticDemo;
import fem2.Constraint;
import fem2.Debugger;
import fem2.Element;
import fem2.MaterialModel;
import fem2.Mesh;
import fem2.MeshPart;
import fem2.MeshUtilities;
import fem2.Model;
import fem2.StringUtilities;
import fem2.analysis.Analysis;
import fem2.analysis.LinearStaticAnalysis;
import fem2.element.MatlabStructuralElement;
import fem2.element.StructuralElement;
import fem2.enu.EchoLevelType;
import fem2.enu.SolverType;
import fem2.enu.State;
import fem2.enu.StressType;
import fem2.material.MLSrecoveryMM;
import fem2.material.SPRrecoveryMM;
import fem2.material.StVenantKirchhoffMM;
import fem2.mesh_and_topology.LineSpatialCriteria;
import fem2.mesh_and_topology.SpatialCriteria;
import fem2.observer.GidStressObserver;
import fem2.observer.TimeStepObserver;
import fem2.pre_and_post.GidPost;
import fem2.pre_and_post.PatchMeshGenerator;
import fem2.pre_and_post.PatchMeshGenerator.PatchType;
import fem2.strategies.Strategy;

/**
 * Lshape with structured mesh with mesh is created by joining two meshes
 * 
 * @author hbui
 * 
 */
public class Lshape extends AbstractStructuralStaticDemo {

	public Lshape() {
		projectDir = "/home/hbui/kratos_janosch";
		projectName = "Lshape.gid";
		meshFileName = "Lshape-structured";
	}

	@Test
	public void writeMesh1() throws IOException {
		Mesh mesh = createMesh();
		Model m = new Model(mesh);

		for (int i = 0; i < mesh.countFaces(); i++) {
			m.addElement(new MatlabStructuralElement(mesh.getFace(i)));
		}

		GidPost p = new GidPost(projectDir, projectName);
		p.writeMesh(m, 1);
	}

	@Override
	public Mesh createMesh() {
		PatchMeshGenerator p1 = new PatchMeshGenerator(41, 21, 0, 0, 25, 25);
		p1.setType(PatchType.TRIANGLE_LEFT_TO_RIGHT);
		Mesh mesh1 = p1.getMesh(2);

		PatchMeshGenerator p2 = new PatchMeshGenerator(21, 21, 0, 500, 25, 25);
		p2.setType(PatchType.TRIANGLE_LEFT_TO_RIGHT);
		Mesh mesh2 = p2.getMesh(2);

		SpatialCriteria c = new LineSpatialCriteria(0, 500, 1, 0);

		mesh1 = MeshUtilities.joinMesh(mesh1, mesh2, c);

		return mesh1;
	}

	@Override
	public Model createConditions(Model m) {
		Mesh mesh = m.getMesh();
		Constraint c1 = new Constraint(false, false);
		Constraint c2 = new Constraint(true, false);
		c2.setValue(1, -0.1);
		mesh.setConstraint(c1, MeshUtilities.seekNodesOnSurface(mesh, 0, 1, -1000));
		MeshUtilities.seekNode(mesh, 1000, 500).setConstraint(c2);
		return m;
	}

	@Override
	public MaterialModel createMaterial(Model m) {
		double E = 25850;
		double nu = 0.18;
		double t = 200;
		double rho = 7.85e-6;
		State ss = State.PLANE_STRESS;
		return new MLSrecoveryMM(m,
				new SPRrecoveryMM(m, new StVenantKirchhoffMM(E, nu, t, rho, ss)), 50);
	}

	@Override
	public Element createElement(MeshPart mp, MaterialModel mm) {
		return new StructuralElement(mp, mm);
	}

	@Override
	public void addObservers(Model m, Strategy s, TimeStepObserver o) {
		super.addObservers(m, s, o);

		if (meshFileName == null) {
			throw new Error("mesh file name was not set");
		}

		String meshName = StringUtilities.getFileName(meshFileName);

		s.addObserver(new GidStressObserver(m, o, projectDir, projectName, meshName,
				StressType.RECOVER_STRESS_ZZ));

		s.addObserver(new GidStressObserver(m, o, projectDir, projectName, meshName,
				StressType.RECOVER_STRESS_MLS));
	}

	@Override
	public void run() {
		Model m = createModel();

		Analysis an = new LinearStaticAnalysis(m);
		// an.getStrategy().setSolverType(SolverType.PETSC_SOLVER);
		Strategy s = an.getStrategy();
		s.setSolverType(SolverType.UMFPACK_SOLVER);
		s.setEchoLevel(EchoLevelType.OUTPUT, EchoLevelType.AUX1);
		an.getModel().setEchoLevel(EchoLevelType.AUX1);

		addObservers(m, s, new TimeStepObserver(s));

		an.run();

		// postProcess(m);

		Debugger.warn("Analysis completed");
	}

	public static void main(String[] args) {
		AbstractStructuralStaticDemo demo = new Lshape();

		demo.run();
	}
}
